﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using Dokan;

namespace MirrorDrive
{
    public class FileHandle : IDisposable 
    {
        public int Id { get; private set; }
        public string Path { get; private set; }

        public FileStream fileStream;

        internal FileHandle(int id, string path)
        {
            this.Id = id;
            this.Path = path;
        }

        ~FileHandle()
        {
            Dispose();
        }

        public void Dispose()
        {
            if (fileStream != null)
            {
                fileStream.Close();
                fileStream = null;
            }
        }
    }
    public class FileHandleManager : IDisposable
    {
        private Random _rnd;
        private SortedList<int, FileHandle> _handles = new SortedList<int, FileHandle>();

        public FileHandleManager()
        {
            _rnd = new Random(System.Guid.NewGuid().GetHashCode());
        }
        ~FileHandleManager()
        {
            Dispose();
        }

        private int GenerateId()
        {
            lock (_handles)
            {
                int id = _rnd.Next(int.MinValue, int.MaxValue);
                while (id == 0 || _handles.ContainsKey(id)) id = _rnd.Next(int.MinValue, int.MaxValue);
                return id;
            }
        }

        public FileHandle AddHandle(string path)
        {
            lock (_handles)
            {
                FileHandle handle = new FileHandle(GenerateId(), path);

               // Logger.Info("{0}: AddHandle: " + path + ", handle: {1}", new StackTrace().GetFrame(1).GetMethod().Name, handle.Id);
                _handles.Add(handle.Id, handle);

                return handle;
            }
        }
        public FileHandle GetHandle(DokanFileInfo info)
        {
            lock (_handles)
            {
               // Logger.Info("{0}: GetHandle: handle: {1}", new StackTrace().GetFrame(1).GetMethod().Name, info.Context != null ? ((int)info.Context).ToString() : "NULL");
                if (info == null || info.Context == null || info.Context.GetType() != typeof(int))
                    return null;
                if (_handles.ContainsKey((int)info.Context))
                    return _handles[(int)info.Context];
                return null;
            }
        }
        public void RemoveHandle(FileHandle handle)
        {
            lock (_handles)
            {
               // Logger.Info("{0}: RemoveHandle: handle: {1}", new StackTrace().GetFrame(1).GetMethod().Name, handle.Id);
                if (_handles.ContainsKey(handle.Id)) _handles.Remove(handle.Id);
            }
        }

        public void Clean()
        {
            lock (_handles)
            {
                for (int i = 0; i < _handles.Count; i++)
                {
                    if (_handles.Values[i].fileStream != null)
                        try
                        {
                            _handles.Values[i].fileStream.Close();
                        }
                        catch (Exception) { }
                }
                _handles.Clear();
            }
        }

        public void Dispose()
        {
            Clean();
        }
    }
}
